#include <stan/math/rev.hpp>
#include <test/unit/math/expect_near_rel.hpp>
#include <gtest/gtest.h>
#include <boost/math/differentiation/finite_difference.hpp>
#include <boost/math/special_functions/digamma.hpp>
#include <algorithm>
#include <limits>
#include <vector>

namespace neg_binomial_2_log_test_internal {
struct TestValue {
  int n;
  double eta;
  double phi;
  double value;
  double grad_eta;
  double grad_phi;

  TestValue(int _n, double _eta, double _phi, double _value, double _grad_eta,
            double _grad_phi)
      : n(_n),
        eta(_eta),
        phi(_phi),
        value(_value),
        grad_eta(_grad_eta),
        grad_phi(_grad_phi) {}
};

// Test data generated in Mathematica (Wolfram Cloud). The code can be re-ran at
// https://www.wolframcloud.com/obj/martin.modrak/Published/neg_binomial_2_log_lpmf.nb
// but is also presented below for convenience:
//
// toCString[x_] := ToString[CForm[N[x, 24]]];
// nb2log[n_,logmu_,phi_]:= LogGamma[n + phi] - LogGamma[n + 1] -
//  LogGamma[phi] + n * (logmu - Log[Exp[logmu] + phi]) +
//  phi * (Log[phi] - Log[Exp[logmu] + phi])
// nb2logdmu[n_,logmu_,phi_]= D[nb2log[n, logmu, phi],logmu];
// nb2logdphi[n_,logmu_,phi_]= D[nb2log[n, logmu, phi],phi];
// logmus= SetPrecision[{-36,-26.1, -4.5,-0.2,2.0,13.4, 84.3}, Infinity];
// phis=  SetPrecision[{0.0001,0.084,3.76,461.0, 142311.0}, Infinity];
// ns = {0,7,11,2338,9611};
// out = "std::vector<TestValue> testValues = {\n";
// For[k = 1, k <= Length[ns], k++, {
//   For[i = 1, i <= Length[logmus], i++, {
//     For[j = 1, j <= Length[phis], j++, {
//       clogmu = logmus[[i]];
//       cphi = phis[[j]];
//       cn=ns[[k]];
//       val = nb2log[cn,clogmu,cphi];
//       ddmu= nb2logdmu[cn,clogmu,cphi];
//       ddphi= nb2logdphi[cn,clogmu,cphi];
//       out = StringJoin[out,"  {",ToString[cn],",",toCString[clogmu],",",
//         toCString[cphi],",", toCString[val],",",toCString[ddmu],",",
//         toCString[ddphi],"},\n"];
//     }]
//   }]
// }]
// out = StringJoin[out,"};\n"];
// out

std::vector<TestValue> testValues = {
    {0, -36., 0.000100000000000000004792174, -2.31952283024087929523226e-16,
     -2.31952283023818920215225e-16, -2.69009308000224930599517e-24},
    {0, -36., 0.0840000000000000052180482, -2.3195228302435661858205e-16,
     -2.31952283024356298332874e-16, -3.81249019275872869665102e-30},
    {0, -36., 3.75999999999999978683718, -2.31952283024356931676723e-16,
     -2.31952283024356924522221e-16, -1.9027933171192913158222e-33},
    {0, -36., 461., -2.31952283024356938772873e-16,
     -2.3195228302435693871452e-16, -1.26580106437037714160219e-37},
    {0, -36., 142311., -2.31952283024356938831037e-16,
     -2.31952283024356938830848e-16, -1.32828224194512041655272e-42},
    {0, -26.1000000000000014210855, 0.000100000000000000004792174,
     -4.62289481781287824178924e-12, -4.62289471095709740559354e-12,
     -1.06855780836195688701657e-15},
    {0, -26.1000000000000014210855, 0.0840000000000000052180482,
     -4.62289492454145310046865e-12, -4.62289492441424382973675e-12,
     -1.51439608014165778339631e-21},
    {0, -26.1000000000000014210855, 3.75999999999999978683718,
     -4.62289492466582046196526e-12, -4.6228949246629785527253e-12,
     -7.55826925521030645308565e-25},
    {0, -26.1000000000000014210855, 461., -4.62289492466863919207562e-12,
     -4.62289492466861601294603e-12, -5.02801075764912450865117e-29},
    {0, -26.1000000000000014210855, 142311., -4.62289492466866229611911e-12,
     -4.62289492466866222103301e-12, -5.27619828240266701257698e-34},
    {0, -4.5, 0.000100000000000000004792174, -0.000471930181119562098823563,
     -0.0000991078594800272766579705, -3.728223216395348042993},
    {0, -4.5, 0.0840000000000000052180482, -0.0104333684327369739264569,
     -0.0098114347031002672745465, -0.00740397297186555491995328},
    {0, -4.5, 3.75999999999999978683718, -0.0110926179127638047017042,
     -0.0110762714687203261403217, -4.34745852220174529502355e-6},
    {0, -4.5, 461., -0.0111088626902796869123984, -0.0111087288444673011605548,
     -2.90337987821587513149328e-10},
    {0, -4.5, 142311., -0.0111089961046503927849115,
     -0.0111089956710585016382076, -3.04679112048052440606817e-15},
    {0, -0.20000000000000001110223, 0.000100000000000000004792174,
     -0.000901046250479348295492963, -0.000099987787464060911106451,
     -8.010584630152873459984},
    {0, -0.20000000000000001110223, 0.0840000000000000052180482,
     -0.199467033424133669556274, -0.0761837159352978552652188,
     -1.46765854153375960277075},
    {0, -0.20000000000000001110223, 3.75999999999999978683718,
     -0.740730806872720638510927, -0.672332093234306416324947,
     -0.0181911472442591026765043},
    {0, -0.20000000000000001110223, 461., -0.818004584479470198072977,
     -0.81727927438862128024214, -1.57334076106055928597981e-6},
    {0, -0.20000000000000001110223, 142311., -0.818728397963215257316515,
     -0.818726042857481443695725, -1.65490069904197201165846e-11},
    {0, 2., 0.000100000000000000004792174, -0.00112103539054129295184384,
     -0.000099998646665483029681996, -10.2103674387580987323199},
    {0, 2., 0.0840000000000000052180482, -0.377012371003043676678775,
     -0.0830558079711177822673545, -3.49948289323721281132084},
    {0, 2., 3.75999999999999978683718, -4.08687891675795882940335,
     -2.49194646483517166950394, -0.424184162745422141042474},
    {0, 2., 461., -7.33046427302122464456484, -7.27249028826061546955612,
     -0.000125757016834293221277066},
    {0, 2., 142311., -7.38886427869112561814738, -7.38867246509109332505865,
     -1.34784802321881715908971e-9},
    {0, 13.4000000000000003552714, 0.000100000000000000004792174,
     -0.00226103403721276985381512, -0.000099999999984848563673037,
     -21.6103403722792118658158},
    {0, 13.4000000000000003552714, 0.0840000000000000052180482,
     -1.33366284302251745111466, -0.0839999893091445105829689,
     -14.876938734683010272656},
    {0, 13.4000000000000003552714, 3.75999999999999978683718,
     -45.4042061406096035346291, -3.75997857962063060636234,
     -11.0755924364332381088221},
    {0, 13.4000000000000003552714, 461., -3350.22538971724911576917,
     -460.678224812138394142983, -6.26799818851433996014357},
    {0, 13.4000000000000003552714, 142311., -246124.815117870661913638,
     -117068.49513614471120162, -0.906861170125471331885925},
    {0, 84.2999999999999971578291, 0.000100000000000000004792174,
     -0.00935103403719761843271571, -0.000100000000000000004792174,
     -92.5103403719761798459793},
    {0, 84.2999999999999971578291, 0.0840000000000000052180482,
     -7.28926283233166137753023, -0.0840000000000000052180482,
     -85.7769384801388205324283},
    {0, 84.2999999999999971578291, 3.75999999999999978683718,
     -311.988184720169192006433, -3.75999999999999978683718,
     -81.9755810425981940674846},
    {0, 84.2999999999999971578291, 461., -36034.8035021785437227894, -461.,
     -77.1666019570033486394563},
    {0, 84.2999999999999971578291, 142311., -1.03081876937799361823842e7,
     -142311., -71.4342299174339030881957},
    {7, -36., 0.000100000000000000004792174, -198.683622924671001775538,
     6.99999999998376310823605, -59997.5501489646175798213},
    {7, -36., 0.0840000000000000052180482, -238.883518369596162432722,
     6.9999999999999804386908, -69.0960424923444586909594},
    {7, -36., 3.75999999999999978683718, -256.751996432901803890657,
     6.99999999999999933622166, -0.718640295127228617069051},
    {7, -36., 461., -260.47982082426917795879, 6.99999999999999976452566,
     -0.0000978945853445233788324339},
    {7, -36., 142311., -260.525013799174310121032, 6.99999999999999976803631,
     -1.03688150994232402700446e-9},
    {7, -26.1000000000000014210855, 0.000100000000000000004792174,
     -129.383623248262034973091, 6.99999967639274733829224,
     -59997.5469131006865090386},
    {7, -26.1000000000000014210855, 0.0840000000000000052180482,
     -169.583518369986016957648, 6.9999999996101358613744,
     -69.0960424877584835201958},
    {7, -26.1000000000000014210855, 3.75999999999999978683718,
     -187.451996432915042522719, 6.99999999998677065175815,
     -0.718640295124939781566091},
    {7, -26.1000000000000014210855, 461., -191.17982082427388076164,
     6.99999999999530690927387, -0.000097894585344371117922657},
    {7, -26.1000000000000014210855, 142311., -191.225013799178942958982,
     6.99999999999537687768416, -1.03688150994072626043362e-9},
    {7, -4.5, 0.000100000000000000004792174, -11.2192075332052297804221,
     0.0623507285386109391248531, 9374.22326367570748540949},
    {7, -4.5, 0.0840000000000000052180482, -19.2633991074236276185347,
     6.17256900670521084397013, -59.3698802916059729529247},
    {7, -4.5, 3.75999999999999978683718, -36.2837402011840741159725,
     6.96830301037142800168473, -0.713160409032598892878726},
    {7, -4.5, 461., -39.9910983681716742384461, 6.9887225919756817853728,
     -0.0000975289772446567319934955},
    {7, -4.5, 142311., -40.0361233417087705744711, 6.98889045789915253328171,
     -1.03304486908480829056641e-9},
    {7, -0.20000000000000001110223, 0.000100000000000000004792174,
     -11.1577615044596219717133, 0.000754889728272497048508259,
     9985.89049108549401489409},
    {7, -0.20000000000000001110223, 0.0840000000000000052180482,
     -5.10523818836474804913996, 0.575173289456547933675185,
     5.01538223526623988873864},
    {7, -0.20000000000000001110223, 3.75999999999999978683718,
     -8.27174735895246138021499, 5.07598581829756986530093,
     -0.403937269906561294876212},
    {7, -0.20000000000000001110223, 461., -10.7102463026561453773833,
     6.1703108450892087653941, -0.0000725484455802695111298855},
    {7, -0.20000000000000001110223, 142311., -10.7437824687875434412923,
     6.18123368560834338804528, -7.70447935296972460390227e-10},
    {7, 2., 0.000100000000000000004792174, -11.1572212979358090452568,
     -5.26523047722532179308571e-6, 9991.29214927237179177473},
    {7, 2., 0.0840000000000000052180482, -4.67822832418615765300115,
     -0.00437313889759920793061993, 9.8011095064000150019666},
    {7, 2., 3.75999999999999978683718, -2.44742652447511137215548,
     -0.131208500432565998079953, 0.0910218281904859865055242},
    {7, 2., 461., -1.92159366542738408699561, -0.382918557279757136122044,
     0.0000158891115286490464064998},
    {7, 2., 142311., -1.91424152166072074784582, -0.38903589945144240315715,
     1.69074180881189252797788e-10},
    {7, 13.4000000000000003552714, 0.000100000000000000004792174,
     -11.1582665635858573490992, -0.0000999989393839702240949489,
     9980.83949989472447227895},
    {7, 13.4000000000000003552714, 0.0840000000000000052180482,
     -5.55575146449510519129741, -0.083999098404519957659751,
     -0.639658499701806072156294},
    {7, 13.4000000000000003552714, 3.75999999999999978683718,
     -40.8853097501782241578175, -3.75993870125478372781648,
     -9.93254120984925579863814},
    {7, 13.4000000000000003552714, 461., -3315.77631190381925371792,
     -460.673338854838977134308, -6.25292229992679818636882},
    {7, 13.4000000000000003552714, 142311., -246051.646530372853518603,
     -117067.253506656850199859, -0.906820707877630374849315},
    {7, 84.2999999999999971578291, 0.000100000000000000004792174,
     -11.1653565625252413192581, -0.000100000000000000004792174,
     9909.93951050103628769457},
    {7, 84.2999999999999971578291, 0.0840000000000000052180482,
     -11.5113505628995678711385, -0.0840000000000000052180482,
     -71.5396476391501811780814},
    {7, 84.2999999999999971578291, 3.75999999999999978683718,
     -307.469248451258373600901, -3.75999999999999978683718,
     -80.8325192100658482257719},
    {7, 84.2999999999999971578291, 461., -36000.3495367018363608841, -461.,
     -77.151515469809951297333},
    {7, 84.2999999999999971578291, 142311., -1.03081131584031573940356e7,
     -142311., -71.4341807304248851244502},
    {11, -36., 0.000100000000000000004792174, -306.294198663985101325787,
     10.9999999999744850169151, -99997.0711864556783212622},
    {11, -36., 0.0840000000000000052180482, -373.387720780818404406357,
     10.999999999999969393344, -116.240975127892379549188},
    {11, -36., 3.75999999999999978683718, -405.018198139691527464642,
     10.9999999999999990894639, -1.45345494122108727163354},
    {11, -36., 461., -413.383897627979795451303, 10.9999999999999997625131,
     -0.000254934049399102214755753},
    {11, -36., 142311., -413.501921377875076957036, 10.9999999999999997680298,
     -2.71559116633421423577824e-9},
    {11, -26.1000000000000014210855, 0.000100000000000000004792174,
     -197.394199172482654828876, 10.9999994914769589000084,
     -99997.0661015266437808503},
    {11, -26.1000000000000014210855, 0.0840000000000000052180482,
     -264.487720781428391423827, 10.9999999993899980078309,
     -116.240975120685847137987},
    {11, -26.1000000000000014210855, 3.75999999999999978683718,
     -296.118198139709689507612, 10.999999999981852678434,
     -1.45345494121749053012889},
    {11, -26.1000000000000014210855, 461., -304.483897627984544048369,
     10.9999999999952667973873, -0.000254934049398862947611818},
    {11, -26.1000000000000014210855, 142311., -304.601921377879715609259,
     10.9999999999953767477464, -2.71559116633170345973834e-9},
    {11, -4.5, 0.000100000000000000004792174, -11.706990517292534287664,
     0.0980363493375200627828593, 9017.8460181027726944107},
    {11, -4.5, 0.0840000000000000052180482, -28.2644285868714287029341,
     9.70535783036710290753852, -100.952775113605121643751},
    {11, -4.5, 3.75999999999999978683718, -58.5617425653278014914233,
     10.9565197428515127604419, -1.44484120738179930405144},
    {11, -4.5, 461., -66.8952715611464156307853, 10.9886262038729098348204,
     -0.0002543593564776044431017},
    {11, -4.5, 142311., -67.0130312326551432919643, 10.9888901456535588389502,
     -2.70956041824890637536164e-9},
    {11, -0.20000000000000001110223, 0.000100000000000000004792174,
     -11.6101872629383735675807, 0.00124339116583624445400238,
     9981.48443912601296955335},
    {11, -0.20000000000000001110223, 0.0840000000000000052180482,
     -5.90787076264096269638241, 0.947377292537602670212559,
     1.05849718208658084906379},
    {11, -0.20000000000000001110223, 3.75999999999999978683718,
     -14.1259605624152918587705, 8.36073891060149916908714,
     -0.948526674591890563801079},
    {11, -0.20000000000000001110223, 461., -20.4214207600281899855949,
     10.1632194847908259343291, -0.000214205349334668674488331},
    {11, -0.20000000000000001110223, 142311., -20.520713059859749302951,
     10.1812106733031004347544, -2.2874532593255647910321e-9},
    {11, 2., 0.000100000000000000004792174, -11.6092126588923464290597,
     0.0000488681502017790827148631, 9991.22977788173817623571},
    {11, 2., 0.0840000000000000052180482, -5.13540078317237206980856,
     0.0405883862872685488332284, 9.73996823769877214616492},
    {11, 2., 3.75999999999999978683718, -3.06137175973074859416703,
     1.21778462208320867130519, 0.0612622027041340431507753},
    {11, 2., 461., -2.88927536521627684556178, 3.55397957470930476869743,
     -4.26994469309227722196226e-6},
    {11, 2., 142311., -2.89135678253022200706033, 3.61075642377121526650085,
     -5.03190674865121337520085e-11},
    {11, 13.4000000000000003552714, 0.000100000000000000004792174,
     -11.6102037914014672054394, -0.0000999983333263254586217559,
     9981.31845625030445310433},
    {11, 13.4000000000000003552714, 0.0840000000000000052180482,
     -5.96770830536101890173932, -0.0839985893161630702750551,
     -0.165549576777919563836645},
    {11, 13.4000000000000003552714, 3.75999999999999978683718,
     -39.8538584150632717115069, -3.759915913617156940076,
     -9.60353212925099392334374},
    {11, 13.4000000000000003552714, 461., -3300.14958948598756276581,
     -460.670546879239310272208, -6.24440860614920345254555},
    {11, 13.4000000000000003552714, 142311., -246013.941380067564168339,
     -117066.544004092358198853, -0.906797587679355764396099},
    {11, 84.2999999999999971578291, 0.000100000000000000004792174,
     -11.617293789734793530787, -0.000100000000000000004792174,
     9910.41847291719271617468},
    {11, 84.2999999999999971578291, 0.0840000000000000052180482,
     -11.9233068946770922978236, -0.0840000000000000052180482,
     -71.065532655650617438992},
    {11, 84.2999999999999971578291, 3.75999999999999978683718,
     -306.43777432844088456675, -3.75999999999999978683718,
     -80.503504068925664332461},
    {11, 84.2999999999999971578291, 461., -35984.7200213335603843011, -461.,
     -77.1429957196861533815963},
    {11, 84.2999999999999971578291, 142311., -1.03080746722304058304262e7,
     -142311., -71.4341526246487950815918},
    {2338, -36., 0.000100000000000000004792174, -62651.1907684420448777443,
     2337.99999999457695539095, -2.33699916660572733525724e7},
    {2338, -36., 0.0840000000000000052180482, -78386.4573396010374044213,
     2337.99999999999354376284, -27813.2247691071302770408},
    {2338, -36., 3.75999999999999978683718, -87244.5784991555256038266,
     2337.99999999999985553814, -615.235652274809944062375},
    {2338, -36., 461., -97261.3541997290761812182, 2337.99999999999999859168,
     -3.26705772262828347042341},
    {2338, -36., 142311., -99951.6902594622698079577, 2337.99999999999999976424,
     -0.000133435966326975414974749},
    {2338, -26.1000000000000014210855, 0.000100000000000000004792174,
     -39504.990876519910618993, 2337.99989191671703492836,
     -2.33699905852787203745752e7},
    {2338, -26.1000000000000014210855, 0.0840000000000000052180482,
     -55240.2573397297094689766, 2337.99999987132480170888,
     -27813.2247675754145700052},
    {2338, -26.1000000000000014210855, 3.75999999999999978683718,
     -64098.3784991584079601655, 2337.99999999712082169713,
     -615.235652274045473004386},
    {2338, -26.1000000000000014210855, 461., -74115.1541997291075706003,
     2337.99999999997193170739, -3.26705772262823261527954},
    {2338, -26.1000000000000014210855, 142311., -76805.4902594622778290634,
     2337.99999999999530115643, -0.000133435966326974881320714},
    {2338, -4.5, 0.000100000000000000004792174, -37.9188749421642944369079,
     20.858146249102902750828, -198577.847904345129887008},
    {2338, -4.5, 0.0840000000000000052180482, -5029.86319434730944140515,
     2064.90525599567281088845, -24562.2210710608448107488},
    {2338, -4.5, 3.75999999999999978683718, -13604.4870759968535893564,
     2331.10160386314082116743, -613.403922615515723001624},
    {2338, -4.5, 461., -23614.4216481166468801215, 2337.93255242508532760098,
     -3.26693551284037806579056},
    {2338, -4.5, 142311., -26304.7015509659310958491, 2337.98870849677942716161,
     -0.000133434683874347561598764},
    {2338, -0.20000000000000001110223, 0.000100000000000000004792174,
     -17.2530056900344775246763, 0.285429102468546297600207,
     7145.03240130482692470614},
    {2338, -0.20000000000000001110223, 0.0840000000000000052180482,
     -238.089236939508565582574, 217.47705608494119565083,
     -2571.27861575441500369895},
    {2338, -0.20000000000000001110223, 3.75999999999999978683718,
     -4005.5119497678293099549, 1919.26585035841237164672,
     -504.067189818768777258691},
    {2338, -0.20000000000000001110223, 461., -13565.92078287865980031,
     2333.03782063120661396226, -3.25806818947358951236853},
    {2338, -0.20000000000000001110223, 142311., -16252.1224385913391334784,
     2337.1678232647280123578, -0.000133341466693716057784701},
    {2338, 2., 0.000100000000000000004792174, -16.9993203274403325176464,
     0.0315409623602125914052141, 9681.71391098754441853037},
    {2338, 2., 0.0840000000000000052180482, -36.345344890082340900417,
     26.196955662584086046202, -296.248198078484197433633},
    {2338, 2., 3.75999999999999978683718, -945.921470460610089695847,
     785.994533645635122586109, -203.555176892467693501323},
    {2338, 2., 461., -8461.86172575984929863877, 2293.84446785934606789742,
     -3.18717688126682423770834},
    {2338, 2., 142311., -11115.2005139685862037106, 2330.48994045855231459004,
     -0.000132584343734508495425318},
    {2338, 13.4000000000000003552714, 0.000100000000000000004792174,
     -16.9688195052148641926364, -0.0000996457592914831445917036,
     9986.7200057158703803923},
    {2338, 13.4000000000000003552714, 0.0840000000000000052180482,
     -10.8734665707860518042194, -0.0837024271645438342281827,
     5.22808308495811843394431},
    {2338, 13.4000000000000003552714, 3.75999999999999978683718,
     -25.5045023028520732667892, -3.74665920542777317204743,
     -4.50627645969873246867534},
    {2338, 13.4000000000000003552714, 461., -2105.32744445484601087282,
     -459.046315074133113245574, -4.46701233139860018126931},
    {2338, 13.4000000000000003552714, 142311., -234622.84254414070827656,
     -116653.790887199136613496, -0.893479868994494336336804},
    {2338, 84.2999999999999971578291, 0.000100000000000000004792174,
     -16.9759091509741556489599, -0.000100000000000000004792174,
     9915.82354812310706660278},
    {2338, 84.2999999999999971578291, 0.0840000000000000052180482,
     -16.8287689979316593747652, -0.0840000000000000052180482,
     -65.668374254014350440872},
    {2338, 84.2999999999999971578291, 3.75999999999999978683718,
     -292.075161470279026145921, -3.75999999999999978683718,
     -75.4027226791102688967341},
    {2338, 84.2999999999999971578291, 461., -34788.2730773814556666438, -461.,
     -75.3620761655318490321712},
    {2338, 84.2999999999999971578291, 142311., -1.02962292135863589242571e7,
     -142311., -71.4179345460698058518492},
    {9611, -36., 0.000100000000000000004792174, -257493.798714111504824811,
     9610.99999997770706584663, -9.60999902521143419375755e7},
    {9611, -36., 0.0840000000000000052180482, -322200.978630068417237347,
     9610.999999999973460561, -114395.144355373590193239},
    {9611, -36., 3.75999999999999978683718, -358701.177684561134391123,
     9610.99999999999940687087, -2548.13160475324762913113},
    {9611, -36., 461., -403079.072217515117383779, 9610.99999999999999493227,
     -17.7630043020635701626676},
    {9611, -36., 142311., -424212.312866130535985746, 9610.99999999999999975238,
     -0.00218253709318427116222024},
    {9611, -26.1000000000000014210855, 0.000100000000000000004792174,
     -162344.899158395651111601, 9610.99955569358470701868,
     -9.60999858092731645759248e7},
    {9611, -26.1000000000000014210855, 0.0840000000000000052180482,
     -227052.078630597345206472, 9610.99999947105914950335,
     -114395.144349077046283779},
    {9611, -26.1000000000000014210855, 3.75999999999999978683718,
     -263552.277684572968739345, 9610.99999998817871670057,
     -2548.13160475010505798557},
    {9611, -26.1000000000000014210855, 461., -307930.172217515232038494,
     9610.99999999989899826967, -17.7630043020633611084385},
    {9611, -26.1000000000000014210855, 142311., -329063.412866130554578654,
     9610.999999999995064897, -0.00218253709318426896848674},
    {9611, -4.5, 0.000100000000000000004792174, -104.508893420504154556264,
     85.743526266719416841998, -847430.234306281205498662},
    {9611, -4.5, 0.0840000000000000052180482, -20648.2403016158121274787,
     8488.39853461890805547167, -101030.965402842249733567},
    {9611, -4.5, 3.75999999999999978683718, -55983.0428066363797886683,
     9582.67667769505493377765, -2540.60175643222855702327},
    {9611, -4.5, 461., -100332.814925682181363541, 9610.75729475722022850913,
     -17.7625019237987339653397},
    {9611, -4.5, 142311., -121465.824725374770167655, 9610.98814075622869244341,
     -0.00218253182129617637581483},
    {9611, -0.20000000000000001110223, 0.000100000000000000004792174,
     -19.5547487056230065372451, 1.17364684131883001763989,
     -1735.73121296897564419702},
    {9611, -0.20000000000000001110223, 0.0840000000000000052180482,
     -949.731171379774212295606, 894.23698468706897035991,
     -10626.5306853797828683123},
    {9611, -0.20000000000000001110223, 3.75999999999999978683718,
     -16521.513038999314726487, 7891.768160440031828256,
     -2091.0860971061479068882},
    {9611, -0.20000000000000001110223, 461., -59023.1441094345908559896,
     9593.14395476867203137831, -17.7260454286430745149716},
    {9611, -0.20000000000000001110223, 142311., -80139.3868875039743196636,
     9610.1259811407200125367, -0.00218214857464869223866328},
    {9611, 2., 0.000100000000000000004792174, -18.5112200482628704439815,
     0.129968981779812349901792, 8698.84749102058108657733},
    {9611, 2., 0.0840000000000000052180482, -119.854424704305068624943,
     107.948248829969884782069, -1268.06413157597183571962},
    {9611, 2., 3.75999999999999978683718, -3933.80532649936636751687,
     3238.80127865994241519564, -854.484838151306300912966},
    {9611, 2., 461., -38021.2293458402145037005, 9452.10949634845787633542,
     -17.4342406591600541232224},
    {9611, 2., 142311., -59002.2007387401537465017, 9603.1123321581496224457,
     -0.0021790320685329142613448},
    {9611, 13.4000000000000003552714, 0.000100000000000000004792174,
     -18.3822916425459253100299, -0.0000985437949788883229584548,
     9988.12276030177863802081},
    {9611, 13.4000000000000003552714, 0.0840000000000000052180482,
     -12.1692487377720201796787, -0.0827767772596333470047606,
     6.63081050986194646155585},
    {9611, 13.4000000000000003552714, 3.75999999999999978683718,
     -21.6460442652836866611064, -3.70522558331286636290617,
     -3.10473788018826412150356},
    {9611, 13.4000000000000003552714, 461., -1491.91977767158488399654,
     -453.969805440038841232377, -3.19739819420502413093782},
    {9611, 13.4000000000000003552714, 142311., -212175.813403243944037729,
     -115363.73784931155578397, -0.853487617294708440971187},
    {9611, 84.2999999999999971578291, 0.000100000000000000004792174,
     -18.3893801863409040880501, -0.000100000000000000004792174,
     9917.23732235214127244709},
    {9611, 84.2999999999999971578291, 0.0840000000000000052180482,
     -18.1236255149538125593602, -0.0840000000000000052180482,
     -64.2546271873853975660471},
    {9611, 84.2999999999999971578291, 3.75999999999999978683718,
     -288.17526969257348869956, -3.75999999999999978683718,
     -73.9901645192500912911873},
    {9611, 84.2999999999999971578291, 461., -34169.7871284528721914203, -461.,
     -74.0814500768543374677113},
    {9611, 84.2999999999999971578291, 142311., -1.02723620903825239882665e7,
     -142311., -71.3688772675071099858592},
};

}  // namespace neg_binomial_2_log_test_internal

TEST(ProbDistributionsNegBinomial2Log, derivativesPrecomputed) {
  using neg_binomial_2_log_test_internal::TestValue;
  using neg_binomial_2_log_test_internal::testValues;
  using stan::math::is_nan;
  using stan::math::neg_binomial_2_log_lpmf;
  using stan::math::value_of;
  using stan::math::var;

  for (TestValue t : testValues) {
    int n = t.n;
    var eta(t.eta);
    var phi(t.phi);
    var val = neg_binomial_2_log_lpmf(n, eta, phi);

    std::vector<var> x;
    x.push_back(eta);
    x.push_back(phi);

    std::vector<double> gradients;
    val.grad(x, gradients);

    for (int i = 0; i < 2; ++i) {
      EXPECT_FALSE(is_nan(gradients[i]));
    }

    auto tolerance = [](double x) { return std::max(fabs(x * 1e-8), 1e-14); };

    EXPECT_NEAR(value_of(val), t.value, tolerance(t.value))
        << "value n = " << n << ", eta = " << t.eta << ", phi = " << t.phi;
    EXPECT_NEAR(gradients[0], t.grad_eta, tolerance(t.grad_eta))
        << "grad_mu n = " << n << ", eta = " << t.eta << ", phi = " << t.phi;
    EXPECT_NEAR(gradients[1], t.grad_phi, tolerance(t.grad_phi))
        << "grad_phi n = " << n << ", eta = " << t.eta << ", phi = " << t.phi;
  }
}

TEST(ProbDistributionsNegBinomial2Log, derivativesComplexStep) {
  using boost::math::differentiation::complex_step_derivative;
  using stan::math::is_nan;
  using stan::math::log1p_exp;
  using stan::math::log_sum_exp;
  using stan::math::neg_binomial_2_log_lpmf;
  using stan::math::var;

  std::vector<int> n_to_test = {0, 7, 100, 835, 14238, 385000, 1000000};
  std::vector<double> eta_to_test = {-124.5, -13, -2, 0, 0.536844, 1.26845, 11};

  auto nb2_log_for_test = [](int n, const std::complex<double>& eta,
                             const std::complex<double>& phi) {
    // Using first-order Taylor expansion of lgamma(a + b*i) around b = 0
    // Which happens to work nice in this case, as b is always 0 or the very
    // small complex step
    auto lgamma_c_approx = [](const std::complex<double>& x) {
      return std::complex<double>(lgamma(x.real()),
                                  x.imag() * boost::math::digamma(x.real()));
    };

    const double n_(n);
    return lgamma_c_approx(n_ + phi) - lgamma(n + 1) - lgamma_c_approx(phi)
           + phi * (log(phi) - log(exp(eta) + phi)) - n_ * log(exp(eta) + phi)
           + n_ * eta;
  };

  double phi_cutoff = 1e10;
  for (double eta_dbl : eta_to_test) {
    for (int n : n_to_test) {
      for (double phi_dbl = 1.5; phi_dbl < 1e22; phi_dbl *= 10) {
        var eta(eta_dbl);
        var phi(phi_dbl);
        var val = neg_binomial_2_log_lpmf(n, eta, phi);

        std::vector<var> x;
        x.push_back(eta);
        x.push_back(phi);

        std::vector<double> gradients;
        val.grad(x, gradients);

        EXPECT_TRUE(value_of(val) < 0)
            << "for n = " << n << ", eta = " << eta_dbl
            << ", phi = " << phi_dbl;

        for (int i = 0; i < 2; ++i) {
          EXPECT_FALSE(is_nan(gradients[i]));
        }

        auto nb2_log_eta
            = [n, phi_dbl, nb2_log_for_test](const std::complex<double>& eta) {
                return nb2_log_for_test(n, eta, phi_dbl);
              };
        auto nb2_log_phi
            = [n, eta_dbl, nb2_log_for_test](const std::complex<double>& phi) {
                return nb2_log_for_test(n, eta_dbl, phi);
              };
        double complex_step_deta
            = complex_step_derivative(nb2_log_eta, eta_dbl);
        double complex_step_dphi
            = complex_step_derivative(nb2_log_phi, phi_dbl);

        std::ostringstream message;
        message << ", n = " << n << ", eta = " << eta_dbl
                << ", phi = " << phi_dbl;

        double tolerance_phi;
        double tolerance_eta;
        if (phi < phi_cutoff || n < 100000) {
          tolerance_phi = std::max(1e-10, fabs(gradients[1]) * 1e-8);
        } else {
          tolerance_phi = std::max(1e-8, fabs(gradients[1]) * 1e-5);
        }

        if (phi < phi_cutoff) {
          tolerance_eta = std::max(1e-10, fabs(gradients[0]) * 1e-8);
        } else {
          tolerance_eta = std::max(1e-8, fabs(gradients[0]) * 1e-5);
        }

        EXPECT_NEAR(gradients[0], complex_step_deta, tolerance_eta)
            << "grad_mu" << message.str();

        EXPECT_NEAR(gradients[1], complex_step_dphi, tolerance_phi)
            << "grad_phi" << message.str();
      }
    }
  }
}

TEST(ProbDistributionsNegBinomial2Log, derivativesZeroOne) {
  using stan::math::log1p_exp;
  using stan::math::log_diff_exp;
  using stan::math::log_sum_exp;
  using stan::math::var;
  using stan::test::expect_near_rel;
  using stan::test::relative_tolerance;

  std::vector<double> eta_to_test = {-943, -130, -15, -1, 0, 0.138, 14, 611};
  double phi_start = 1e-8;
  double phi_max = 1e20;
  for (double eta_dbl : eta_to_test) {
    for (double phi_dbl = phi_start; phi_dbl < phi_max;
         phi_dbl *= stan::math::pi()) {
      std::stringstream msg;
      msg << std::setprecision(20) << ", eta = " << eta_dbl
          << ", phi = " << phi_dbl;

      var eta0(eta_dbl);
      var phi0(phi_dbl);
      var val0 = neg_binomial_2_log_lpmf(0, eta0, phi0);

      std::vector<var> x0;
      x0.push_back(eta0);
      x0.push_back(phi0);

      std::vector<double> gradients0;
      val0.grad(x0, gradients0);

      var eta1(eta_dbl);
      var phi1(phi_dbl);
      var val1 = neg_binomial_2_log_lpmf(1, eta1, phi1);

      std::vector<var> x1;
      x1.push_back(eta1);
      x1.push_back(phi1);

      std::vector<double> gradients1;
      val1.grad(x1, gradients1);

      double expected_value_0 = phi_dbl * (-log1p_exp(eta_dbl - log(phi_dbl)));
      expect_near_rel("value, n = 0 " + msg.str(), val0.val(),
                      expected_value_0);

      double expected_deta_0 = -phi_dbl / (1 + phi_dbl / exp(eta_dbl));
      expect_near_rel("deta, n = 0 " + msg.str(), gradients0[0],
                      expected_deta_0);

      double expected_dphi_0 = 1.0 / (1.0 + phi_dbl / exp(eta_dbl))
                               - log1p_exp(eta_dbl - log(phi_dbl));
      expect_near_rel("dphi, n = 0 " + msg.str(), gradients0[1],
                      expected_dphi_0);

      double expected_value_1
          = (phi_dbl + 1) * (-log1p_exp(eta_dbl - log(phi_dbl))) + eta_dbl;
      expect_near_rel("value, n = 1 " + msg.str(), val1.val(),
                      expected_value_1);

      double expected_deta_1
          = exp(log(phi_dbl) - log_sum_exp(eta_dbl, log(phi_dbl)))
            + expected_deta_0;
      expect_near_rel("deta, n = 1 " + msg.str(), gradients1[0],
                      expected_deta_1);

      double expected_dphi_1
          = (1 + phi_dbl) / (phi_dbl + (phi_dbl * phi_dbl) / exp(eta_dbl))
            - log1p_exp(eta_dbl - log(phi_dbl));
      expect_near_rel("dphi, n = 1 " + msg.str(), gradients1[1],
                      expected_dphi_1);
    }
  }
}

TEST(ProbDistributionsNegBinomial2Log, derivatives_diff_sizes) {
  using stan::math::neg_binomial_2_log_lpmf;
  using stan::math::var;

  int N = 100;
  double eta_dbl = 1.5;
  std::vector<double> phi_dbl{2, 4, 6, 8};

  var mu(eta_dbl);
  std::vector<var> phi;
  for (double i : phi_dbl) {
    phi.push_back(var(i));
  }
  var val = neg_binomial_2_log_lpmf(N, mu, phi);

  std::vector<var> x{mu};
  std::vector<double> gradients;
  val.grad(x, gradients);

  double eps = 1e-6;
  double grad_diff = (neg_binomial_2_log_lpmf(N, eta_dbl + eps, phi_dbl)
                      - neg_binomial_2_log_lpmf(N, eta_dbl - eps, phi_dbl))
                     / (2 * eps);
  EXPECT_FLOAT_EQ(grad_diff, gradients[0]);
}
